﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace StringDefs.Common
{
    public static class Common
    {
       

        /// <summary>
        /// Returns the number of words in the string
        /// </summary>
        /// <param name="sentence"></param>
        /// <returns></returns>
        public static int WordCount(this string sentence)
        {
            return sentence.Split(new[] { ',', '.', ';' ,' '}, StringSplitOptions.RemoveEmptyEntries).Length;
        }

        /// <summary>
        /// Checks whether the argument is upper case or not
        /// </summary>
        /// <param name="c"></param>
        /// <returns>True or False depending on the argument</returns>
        public static bool IsUpperCase(this char c)
        {
            if (c >= 'A' && c <= 'Z')
                return true;
            
            return false;
        }

        /// <summary>
        /// Returns the reverse of a string
        /// </summary>
        /// <param name="phrase"></param>
        /// <returns></returns>
        public static string Reverse(this string phrase)
        {
            
            char[] cphrase = phrase.ToCharArray();
            for (int i = phrase.Length - 1, j = 0; i >= 0; i--, j++)
            {
                cphrase[j] = phrase[i];
            }
            return new string(cphrase);
        }

        /// <summary>
        /// Toggles the case of the phrase. If it is passed 
        /// </summary>
        /// <param name="phrase"></param>
        /// <returns></returns>
        public static string ToggleCase(this string phrase)
        {
            string ToggledPhrase = string.Empty;
            for (int i = 0; i < phrase.Length; i++)
            {
                if (IsUpperCase(phrase[i]))
                    ToggledPhrase = ToggledPhrase + phrase[i].ToString().ToLower();
                else
                    ToggledPhrase = ToggledPhrase + phrase[i].ToString().ToUpper();
            }

            return ToggledPhrase;
        }

        /// <summary>
        /// Changes the case of the sentence as in a valid sentence.
        /// </summary>
        /// <param name="sentence"></param>
        /// <returns></returns>
        public static string SentenceCase(this string sentence)
        {

            sentence = sentence.Replace("  "," ").Replace("!", "! ").Replace(".", ". ").Replace("?", "? ").ToLower ();
            StringBuilder senCaseBuilder = new StringBuilder ();
            string NewSentence = string.Empty;
                        
            string[] tokens = sentence.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
            senCaseBuilder.Append(tokens[0][0].ToString ().ToUpper () + tokens[0].Substring(1));

            
            for (int i = 1; i < tokens.Length; i++)
            {
                if (tokens[i - 1].EndsWith("?") || tokens[i - 1].EndsWith(".") || tokens[i - 1].EndsWith("!"))
                {
                    senCaseBuilder.Append(" " + tokens[i][0].ToString().ToUpper() + tokens[i].Substring(1));
                }
                else
                    senCaseBuilder.Append(" " + tokens[i]);             
            }    
            return senCaseBuilder.ToString ();
        }

        /// <summary>
        /// Just changes the initial letter's case. The remaining remain the same
        /// </summary>
        /// <param name="sentence"></param>
        /// <param name="delm"></param>
        /// <returns></returns>
        public static string InitialUpperCase(this string sentence, char delm)
        {
            string NewSentence = string.Empty;
            string[] tokens = sentence.Split(new char[] { delm }, StringSplitOptions.RemoveEmptyEntries);
            foreach (string k in tokens)
                NewSentence = NewSentence + k.Trim()[0].ToString().ToUpper() + k.Trim().Substring(1) + delm.ToString();
            return NewSentence;
        }

       
        /// <summary>
        /// Returns the q grams
        /// </summary>
        /// <param name="sentence">q grams are extracted for this sentence</param>
        /// <param name="q">value for q</param>
        /// <returns></returns>
        public static IList<string> NGrams(this string sentence, int q)
        {
            int total = sentence.Length - q;
            List<string> tokens = new List<string>();
            for (int i = 0; i <= total; i++)
                tokens.Add(sentence.Substring(i, q));
            return tokens;
        }
        /// <summary>
        /// This deletes all the white spaces in the string.
        /// </summary>
        /// <param name="x"></param>
        /// <returns></returns>
        public static string StripWhiteSpaces(this string phrase)
        {
            string temp = string.Empty;
            string[] tokens = phrase.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
            foreach (string k in tokens)
                temp = temp + k;
            return temp;
        }
       
        /// <summary>
        /// Sweep these characters
        /// </summary>
        /// <param name="phrase"></param>
        /// <param name="puncts"></param>
        /// <returns></returns>
        public static string StripChars(this string phrase, char[] puncts)
        {
            string temp = string.Empty;
            string[] tokens = phrase.Split(puncts, StringSplitOptions.RemoveEmptyEntries);
            foreach (string k in tokens)
                temp = temp + k;
            return temp;
        }

        public static string MultiRemove(this string sentence, params string[] words)
        {
            StringBuilder sb = new StringBuilder();
            string[] toks = sentence.Split(' ');

            foreach (string t in toks)
                if (!words.Contains(t))
                    sb.Append(t + " ");
            return sb.ToString ().Trim ();
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="sentence"></param>
        /// <param name="wordsToRemove"></param>
        /// <returns></returns>
        public static string MultiRemove(this string sentence, IList<string> words)
        {
            foreach (string k in words)
                sentence = sentence.Remove(sentence.IndexOf(k));
            return sentence;
        }
        /// <summary>
        /// Returns the number of words in the given sentence.
        /// </summary>
        /// <param name="sentence"></param>
        /// <param name="punctuations"></param>
        /// <returns></returns>
        public static int WordCount(this string sentence, char[] punctuations)
        {
            return sentence.Split(punctuations, StringSplitOptions.RemoveEmptyEntries).Length;
        }

        public static string UnQuote(this string quotation)
        {
            return quotation.Trim(new char[] { '"', '\'' });
        }
        
        /// <summary>
        /// 
        /// </summary>
        /// <param name="quotation"></param>
        /// <returns></returns>
        public static string Quote(this string quotation)
        {
            return " \"" + quotation + "\"";
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="word"></param>
        /// <param name="invalidChars"></param>
        /// <returns></returns>
        public static bool ContainsAnyOf(this string word, char[] invalidChars)
        {
            for (int i = 0; i < word.Length; i++)
                for (int j = 0; j < invalidChars.Length; j++)
                    if (word[i] == invalidChars[j])
                        return true;
            return false;
        }        
        
        public static string StripRepeatChars(this string word)
        {
            
            for (int i = 0; i < word.Length; i++)
                for (int j = 0; j < word.Length; j++)
                    if (i != j)
                        if (word[i] == word[j])
                            word = word.Remove(j);
            return word;
        }
        
        /// <summary>
        /// 
        /// </summary>
        /// <param name="word"></param>
        /// <returns></returns>
        public static string StripConsecutiveRepeatChars(this string word)
        {
            for (int i = 0; i < word.Length; i++)
                for (int j = 0; j < word.Length; j++)
                    if (Math.Abs(i - j) == 1)
                        if (word[i] == word[j])
                            word = word.Remove(j, 1);
            return word;
        }

        public static bool StartsWithAlphabets(this string word)
        {
            List<string> valids = new List<string>();
            char c = 'a';
            for (int i = 0; i < 26; i++, c++)
            {
                valids.Add(c.ToString());
                valids.Add(c.ToString().ToUpper());
            }
            foreach (string k in valids)
                if (word.StartsWith(k))
                    return true;
            return false;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="names"></param>
        /// <returns></returns>
        public static IList<string> AlphabeticalSort(this IList<string> names)
        {

            for (int i = 0; i < names.Count - 1; i++)
            {
                if (names[i].CompareTo(names[i + 1]) > 0)
                {
                    string x = names[i];
                    names[i] = names[i + 1];
                    names[i + 1] = x;
                }
            }
            return names;
        }


        /// <summary>
        /// Returns the IList of alphabests used in the specified argument word.
        /// </summary>
        /// <param name="word">The word whose alphabets are being sought</param>
        /// <returns>IList type</returns>
        public static IList<char> Alphabets(this string word)
        {
            List<char> alphabets = new List<char>();
            for (int i = 0; i < word.Length; i++)
                if (!alphabets.Contains(word[i]))
                    alphabets.Add(word[i]);
            alphabets.Sort();
            return alphabets;
        }

        /// <summary>
        /// Sets the specified number of characters of the string to the specified character.
        /// </summary>
        /// <param name="s">The string whose characters are to be set</param>
        /// <param name="c">The character to be used for setting</param>
        /// <param name="n">Upto n characters </param>
        /// <returns></returns>
        public static string SetChars(this string s, char c, int n)
        {
            char[] temp = s.ToCharArray();
            for (int i = 0; i < n; i++)
                temp[i] = c;
            return new string(temp);
        }
        /// <summary>
        /// Returns the location till which both the strings match with each other.
        /// </summary>
        /// <param name="a">The first string</param>
        /// <param name="b">The second string</param>
        /// <returns></returns>
        public static int SameTill(string a, string b)
        {
            int i;
            int n = a.Length > b.Length ? b.Length : a.Length;
            for (i = 0; i < n; i++)
                if (a[i] != b[i])
                    break;
            return i;
        }
        /// <summary>
        /// Sets all the characters in the string to the specified character
        /// </summary>
        /// <param name="s">The string</param>
        /// <param name="c">The character to set</param>
        /// <returns></returns>
        public static string SetChar(this string s, char c)
        {
            char[] temp = s.ToCharArray();
            for (int i = 0; i < temp.Length; i++)
                temp[i] = c;
            return new string(temp);
        }

        private static Dictionary<char, List<int>> populateCharIndexMap(Dictionary<char, List<int>> charIndexMap1, string word)
        {
            for (int i = 0; i < word.Length; i++)
            {
                if (!charIndexMap1.ContainsKey(word[i]))
                {
                    List<int> indices = new List<int>();
                    indices.Add(i);
                    charIndexMap1.Add(word[i], indices);
                }
                else
                    charIndexMap1[word[i]].Add(i);
            }
            return charIndexMap1;
        }
        /// <summary>
        /// This method should return true if the argument pattern is a sub sequence of the string word
        /// </summary>
        /// <param name="word">The main word</param>
        /// <param name="pattern">The suspected sub-sequece</param>
        /// <returns></returns>
        public static bool IsSubSequence(this string word, string pattern)
        {
            
            Dictionary<char, List<int>> charIndexMap1 = new Dictionary<char, List<int>>();
            Dictionary<char, List<int>> charIndexMap2 = new Dictionary<char, List<int>>();

            charIndexMap1 = populateCharIndexMap(charIndexMap1, word);
            charIndexMap2 = populateCharIndexMap(charIndexMap2, pattern );


            foreach (char c in charIndexMap2.Keys)
            {
                if (charIndexMap1[c][charIndexMap1[c].Count - 1] - charIndexMap2[c][charIndexMap2[c].Count - 1] >= 0)
                {
                    continue;
                }
                else
                    return false;
            }
         
            return true ;
        }

        /// <summary>
        /// Returns true if the argument character is a vowel
        /// </summary>
        /// <param name="c"></param>
        /// <returns></returns>
        public static bool isVowel(this char c)
        {
            return (c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u')
                  || (c == 'A' || c == 'E' || c == 'I' || c == 'O' || c == 'U');
        }
        /// <summary>
        /// This method finds the longest common substring
        /// </summary>
        /// <param name="a">The bigger string </param>
        /// <param name="b">The smaller string</param>
        /// <returns></returns>
        
        static string sub(string a, int x, int y)
        {
            return a.Substring(x, y - x + 1);
        }
        /// <summary>
        /// Reverses a sentence word by word
        /// </summary>
        /// <param name="sentence">The sentence for which the words have to be reversed.</param>
        /// <returns></returns>
        public static string WordReverse(this string sentence)
        {
            string rev = string.Empty;
            if (sentence.IndexOf(' ') == -1)//The sentence is only one word
                return sentence;
            
            
            List<int> windices = new List<int>();//White Space Indices
            for (int i = 0; i < sentence.Length; i++)
            {
                if (sentence[i] == ' ')
                    windices.Add(i);
            }            
            
            if (windices.Count == 1)//There are only two words
                return sentence.Substring (sentence.IndexOf (' ')+1) + " " + sentence.Substring(0, sentence.IndexOf(' '));
           
            rev = sentence.Substring(windices[windices.Count - 1] + 1);
            int latest = windices.Count - 1;
           
            do
            {
                rev = rev + sub(sentence, windices[latest - 1], windices[latest]);
                latest--;
            } while (latest >= 1);

            rev = rev + " " + sub(sentence, 0, windices[0] - 1);
            return rev;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="phrase"></param>
        /// <param name="delm"></param>
        /// <param name="q"></param>
        /// <returns></returns>
        public static string InsertDelimiter(this string phrase, string delm, int  q )
        {
            //greetings
            //gr-eetings
            //gr-ee
            int counter = 0;
            phrase = phrase.Insert(q, delm);
            for (int i = q; i < phrase.Length; i++,counter++)
            {
                if (counter  == q+1 )
                {
                    phrase = phrase.Insert(i, delm);
                    counter = 0;
                }
            }
            return phrase;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="phrase"></param>
        /// <param name="delm"></param>
        /// <returns></returns>
        public static string InsertDelimiter(this string phrase, string delm)//Default Version Q = 2
        {
            int counter = 0;
            int q = 2;
            phrase = phrase.Insert(q, delm);
            for (int i = q; i < phrase.Length; i++, counter++)
            {
                if (counter == q + 1)
                {
                    phrase = phrase.Insert(i, delm);
                    counter = 0;
                }
            }
            return phrase;
        }

        public static string InsertDelimiter(this string phrase)//Default Version Q = 2 and default delimeter = ,
        {
            int counter = 0;
            int q = 2;
            phrase = phrase.Insert(q, ",");
            for (int i = q; i < phrase.Length; i++, counter++)
            {
                if (counter == q + 1)
                {
                    phrase = phrase.Insert(i, ",");
                    counter = 0;
                }
            }
            return phrase;
        }

     

      
    }
}
